/*
 * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "contract.h"
#include <stdlib.h>

#define MAX_BUF_LEN     1024


// *******function declaration*******
//---------------------------------------------contract and encode-------------------------------------------//
//------------the initialization related--------------//

/* Description: argInit, initializes the parameter type structure.
** Input and output: parameter type structure Pointers
** Return value: no */
static void argInit(arg_t* const arg);

/* Description: abiStructInit, which initializes the ABI structure
** Input, output: ABI, structure to initialize
** Return value: NULL returns an error, otherwise returns success */
static contract_err_t abiStructInit(abi_t* const abi);

//------------------------The value is related to hexadecimal format string conversion-------------------------//
/* Description: Convert an array of bytes to a hexadecimal string. For example, f0, F de to the string "0f000fde"
** Input: valbytes, an array of bytes in which each byte does not necessarily contain a string, meaning that each intermediate byte may have a value of 0x00 and cannot be printed as a string
** Vallen, the length of valbytes. If valbytes is itself a string, the length of the string terminator is not included
** strsize, output the size of the byte space occupied by the array STR. And each hexadecimal number is represented by two characters (00-ff), so strsize&gt is required; * vallen + 1 = 2. (And string terminator)
** Output: STR, which stores a hexadecimal string.
Parameter errors return CONTRACT_ERR_PARAMINVALID, especially if strsize < 2*vallen + 1 
Success returns successful CONTRACT_SUCCESS*/
static contract_err_t bytesToHexString(const ql_byte_t* const valbytes, ql_byte_t* const str, const ql_size_t vallen, const ql_size_t strsize);

/* Description: encodeInt64To64Str converts a 64-bit signed integer of numeric type into a hexadecimal string of length 64 (preceded by a '0' to 64 bits, related to EVM encoding). The string does not need to start with 0x.
** Input: intval, the 64-bit value to be converted;
** ressize, the size of the output array res, must be > =65 (including string terminator);
** Output: res, conversion result string. Bits 0-63 are the conversion result, and bits 64 are the end of the string.
** Return value: CONTRACT_ERR_PARAM_INVALID is returned for parameter error
Success returns successful CONTRACT_SUCCESS*/
static contract_err_t encodeInt64To64Str(const ql_int64_t intval, ql_byte_t* const res, const ql_size_t ressize);

/* encodeUint64To64Str, convert the unsigned integer of 64-bit numeric type into hexadecimal string, the specific parameter is similar to encodeInt64To64Str */
static contract_err_t encodeUint64To64Str(ql_uint64_t uintval, ql_byte_t* const res, ql_size_t ressize);

static contract_err_t encodeUint32To64Str(ql_uint32_t uintval, ql_byte_t* const res, ql_size_t ressize);

/* EncodeFuncSelector, hash encoding of function name (according to argument list)
** Input: methodName, the function name. Param cannot be NULL without a '('; otherwise, it can be NULL
** param, a list of types, must have if methodName does not have a '(', otherwise NULL
** Output: encoderes, the result of the hash encoding of the function name
** Return value: Return parameter error, memory allocation failure, or success*/
static contract_err_t encodeFuncSelector(const ql_byte_t* const methodName, const param_t* const param, arg_t* const encoderes);

static contract_err_t encodeFunc(abi_t* const abiroot, ql_byte_t* const methodName, ql_strings_t* const encoderes);

static contract_err_t encodearg(param_t *const inputs, arg_t* const args, ql_strings_t* const encodeRes);

/* GetFuncInputWithoutType: in the abiroot structure, obtain a list of inputs related to this function according to methodName
** Input: methodName, the name of the function to look for, without arguments (that is, without '(' and ')')
** Abiroot, abi structure, where all function information is stored, to find results from
** Output: res, which stores the parameter list information of the function to be sought
** Return value: parameter error (not found, multiple found), success*/
static contract_err_t getFuncInputWithoutType(abi_t* const abiroot, ql_byte_t* const methodName, param_t*const res);

/* MethodNormalize, converts methodName to decoder, intx in string to INT256
** Input: methodName, the function name string to be converted
** ressize, the number of bytes in memory of the string pointer to which the output points
** Output: res, converted string result
** Return value: Error return parameter error, correct return success*/
static contract_err_t methodNormalize(const ql_byte_t* const methodName, ql_byte_t* const res, ql_size_t ressize);

static contract_err_t StrbytesAlign64(arg_t* const arg);

/* Description: Adds a single parameter structure (or list) to the parameter list
** Input: addarg, the parameter to be added to the end of the parameter list
** Output: args, list of parameters to modify
** Return value: args or addarg==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns CONTRACT_SUCCESS successfully*/
static contract_err_t addArg(arg_t* const args, arg_t* const addarg);

static contract_err_t getFuncWithoutType(abi_t* const abiroot, ql_byte_t* const methodName, abi_t*const res);

/* SetTo, set the target address in the CON structure.
** Input: target address to be set. The destination address should be a 42-bit string starting with 0x.
** Output: structure pointer to be modified con;
** Return value: con==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns successful CONTRACT_SUCCESS*/
static contract_err_t setTo(contract_t* const con, const ql_byte_t *const to);

/* Note: setPayload sets the payload in the CON structure.
** Input: payload to be set.
** Output: structure pointer to be modified con;
** Return value: con==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns successful CONTRACT_SUCCESS*/
static contract_err_t setPayload(contract_t* const con, const ql_byte_t *const payload);

static void paramFree(param_t *param);


//---------------------------------------------response and decode-------------------------------------------//

/* decode64HexStrToUint converts a hexadecimal string of length 64 to a uint
** Input: STR, the string to be processed
** Output: retval, the value returned
** return RESPONSE_SUCCESS,
** Parameter error returns RESPONSE_ERR_PARAM_INVALID
Note that since evM has 256-bit values, but C has a maximum of 64 bits, it is also possible to return RESPONSE_ERR_OVERFLOW*/
static response_err_t decode64HexStrToUint(const ql_byte_t* const str, ql_uint64_t* const retval);

/*Decode64HexStrToInt, convert 64 long hexadecimal string to int value. See decode64HexStrToUint for details*/
static response_err_t decode64HexStrToInt(const ql_byte_t* const str, ql_int64_t* const retval);

/*DecodeHexStrToBytes converts hexadecimal values into numeric bytes. For example, "31" becomes 31
** Input: STR, the string to be processed
** strlen, the length of the string to process
** retsize, the total memory size of the returned bytes array
Output: ret, bytes array
** return RESPONSE_SUCCESS,
** Parameter error returns RESPONSE_ERR_PARAM_INVALID. Notice that one of them is strlen/2+1 >; The error caused by retsize is that the bytes array returned is not large enough*/
static response_err_t decodeHexStrToBytes(ql_byte_t* const str, ql_byte_t* const ret, const ql_uint64_t strlen, const ql_uint64_t retsize);

/*The decoding result RES is obtained according to the parameter information linked list corresponding to in and output structures
** Input: params, parameter list information
** in, string information to be decoded
** Output: res, decoding result. If the value is a numeric type, it is stored in bytes or int64
** return RESPONSE_SUCCESS,
** Parameter error returns RESPONSE_ERR_PARAM_INVALID
** RESPONSE_ERR_OVERFLOW, overflow when decoding values*/
static response_err_t decodeFromParam(const param_t* const params, const ql_byte_t* const in, decode_t* const res);

//---------others--------//
//Determine whether the type is numeric, string, or bytes
static DECODE_BASICTYPE getDecodeType(const ql_byte_t* const type);

//Static type length, refers to the array length of integer array, bytesX X refers to. If it is not an array, such as a simple uint256, return 1
static ql_uint64_t StaticTypeLen(const ql_byte_t* const type);

static response_err_t decode64HexStrsToUint64Array(const ql_byte_t*const str, const ql_size_t arraylen, ql_uint64_t*const res, const ql_size_t reslen);

static response_err_t decode64HexStrsToInt64Array(const ql_byte_t* const str, const ql_size_t arraylen, ql_int64_t* const res, const ql_size_t reslen);

/*Description: Allocate the memory of the log structure in the heap and initialize it*/
static eventlog_t* createLog();

static topic_t* createTopic();

/*Description: Release the content of the Topics structure. Refers to the contents of the entire list*/
static void freeTopics(void* ptr);

/*Release the memory of a single log, not the entire list*/
static void freeLog(void* ptr);

/*Release the list contents corresponding to the entire log*/
static void freeLogs(void* ptr);

static response_err_t logFromJson(eventlog_t *const log, cJSON *items);




// *******function definition*******

void CleanContract(contract_t *con) {
    if(con == NULL)return;
    free(con->payload);
    con->payload = NULL;
    free(con->extra);
    con->extra = NULL;
    free(con->version);
    con->version = NULL;
    free(con->extraid);
    con->extraid = NULL;
    free(con->contractname);
    con->contractname = NULL;
}

//Specify the type of virtual machine environment to run
contract_err_t SetVMtype(contract_t* const con, const VM_TYPE type) {
    //check param
    if(con == NULL)return CONTRACT_ERR_PARAM_INVALID;
    con->vmtype = type;
    return CONTRACT_SUCCESS;
}

contract_err_t SetContractName(contract_t* const con, const ql_byte_t *const contractName) {
    //check param
    if(con == NULL )return CONTRACT_ERR_PARAM_INVALID;
    if(con->contractname != NULL) {
        free(con->contractname);
        con->contractname = NULL;
    }
    if(contractName == NULL) {
        con->contractname = (ql_byte_t*)calloc(1, sizeof(ql_byte_t));
        return CONTRACT_SUCCESS;
    }
    //cal length of name
    ql_size_t len = strnlen(contractName, MAX_BUF_LEN);
    //the name can not larger than 1024B
    if(len == MAX_BUF_LEN)return CONTRACT_ERR_OVER_MAX_SIZE;
    //alloc memory
    con->contractname = (ql_byte_t*)calloc(len + 1, sizeof(ql_byte_t));
    if(con->contractname == NULL) return CONTRACT_ERR_ALLOC_MEMORY;
    //set contractName
    memcpy(con->contractname, contractName, len);
    con->contractname[len] = 0;
    return CONTRACT_SUCCESS;
}

//default con->to is "0x0"
static contract_err_t setTo(contract_t* const con, const ql_byte_t *const to) {
    //check param
    if(con == NULL)return CONTRACT_ERR_PARAM_INVALID;
    memset(con->to, 0, sizeof(con->to));
    if(to == NULL){//address is NULL
        memcpy(con->to, ADDR_ZERO, strlen(ADDR_ZERO));
    }else if(strnlen((char*)to, 43) == 42 ) {//valid address
        memcpy(con->to, to, 42);
    } else {//invalid address
        memcpy(con->to, ADDR_ZERO, strlen(ADDR_ZERO));
    }
    con->to[42] = 0;
    return CONTRACT_SUCCESS;
}


static contract_err_t setPayload(contract_t* const con, const ql_byte_t *const payload) {
    if(con == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if(con->payload != NULL) {//free last payload mem
        free(con->payload);
        con->payload = NULL;
    }
    if(payload == NULL){
        con->payload = (ql_byte_t*)calloc(1, sizeof(ql_byte_t));
    } else {
        ql_size_t len = strnlen((char*)payload, 512*MAX_BUF_LEN * 2 + 1);
        if(len == 512*MAX_BUF_LEN * 2 + 1)return CONTRACT_ERR_OVER_MAX_SIZE;
        con->payload = (ql_byte_t*)calloc(len + 1, sizeof(ql_byte_t));
        memcpy(con->payload, payload, len);
    }
    return CONTRACT_SUCCESS;
}

//from, ex and exID are initialized, and all other values are set to default first
contract_err_t ContractInit(contract_t* const con, const ql_byte_t* const from, const ql_byte_t *const ex, const ql_byte_t *const exid) {
    //contract_err_t ret = CONTRACT_SUCCESS;
    //check if Contract struct 
    if(con == NULL) {
        log_debug("can not init contract_t with NULL\n");
        return CONTRACT_ERR_PARAM_INVALID;
    }
    //init from
    if(from == NULL || strnlen((char*)from, 43) != 42)memcpy(con->from, ADDR_ZERO, strlen(ADDR_ZERO)+1);
    else memcpy(con->from, from, 43);
    //init extra
    ql_int32_t len = 0;
    if(ex == NULL || ( len = strlen((char*)ex) ) <= 0) {
        con->extra = NULL;
    } else{
        con->extra = (ql_byte_t*)calloc(len+1, sizeof(ql_byte_t));
        if(con->extra == NULL) {
            CleanContract(con);
            return CONTRACT_ERR_ALLOC_MEMORY;
        }
        memcpy(con->extra, ex, len);
    }
    //init extraid
    len = 0;
    if(exid == NULL || ( len = strlen((char*)exid) ) <= 0) {
        con->extraid = NULL;
    } else {
        con->extraid = (ql_byte_t*)calloc(len+1, sizeof(ql_byte_t));
        if(con->extraid == NULL) {
            CleanContract(con);
            return CONTRACT_ERR_ALLOC_MEMORY;
        }
        memcpy(con->extraid, exid, len);
    }

    //default init
    contract_err_t ret = setTo(con, "\0");
    if(ret != CONTRACT_SUCCESS) {
        CleanContract(con);
        return ret;
    }
    con->value = 0;
    con->payload = (ql_byte_t*)calloc(1, sizeof(ql_byte_t));
    if(con->payload == NULL) {
        CleanContract(con);
        return CONTRACT_ERR_ALLOC_MEMORY;
    }

//timestamp
#if defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
    (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)
    struct timespec cur_time = {0, 0}; 
    clock_gettime(CLOCK_REALTIME, &cur_time);
    con->timestamp = (ql_int64_t)cur_time.tv_sec * 1000000000 + (ql_int64_t)cur_time.tv_nsec;
#else
    con->timestamp = 0;
#endif    
    //nonce
    con->nonce = 1ULL;
    con->opcode = QL_NONE;
    con->vmtype = EVM;
    con->version = StrMalloc("2.5", strlen("2.5"));
    con->contractname = (ql_byte_t*)calloc(1, sizeof(ql_byte_t));
    memcpy(con->simulate, "false\0", strlen("false") + 1);
    //signature
    memset(con->signature, 0, sizeof(con->signature));
    return CONTRACT_SUCCESS;
}


arg_t* CreateArg() {
    arg_t *ret = (arg_t*)calloc(1, sizeof(arg_t));
    if(ret == NULL)return NULL;
    ret->len = 0;
    ret->val = NULL;
    ret->next = NULL;
    return ret;
}

static void argInit(arg_t* const arg) {
    if(arg == NULL)return;
    arg->len = 0;
    arg->val = NULL;
    arg->next = NULL;
}

abi_t* CreateAbi() {
    abi_t* ret = (abi_t*)calloc(1, sizeof(abi_t));
    if(ret == NULL)return NULL;
    ret->type = ABI_FUNCTION;
    ret->name = NULL;
    ret->inputs = NULL;
    ret->outputs = NULL;
    ret->next = NULL;
    return ret;
}

static contract_err_t abiStructInit(abi_t* const abi) {
    if(abi == NULL)return CONTRACT_ERR_PARAM_INVALID;
    abi->type = ABI_FUNCTION;
    abi->name = NULL;
    abi->inputs = NULL;
    abi->outputs = NULL;
    memset(abi->payable, 0, sizeof(abi->payable));
    memset(abi->stateMutability, 0, sizeof(abi->stateMutability));
    memset(abi->anonymous, 0, sizeof(abi->anonymous));
    abi->next = NULL;
    return CONTRACT_SUCCESS;
}




//Convert bytes stored in binary to hex. Because bytes may contain a byte that is 0x00, it is easier to handle as a string
//strsize >= vallen*2+1
static contract_err_t bytesToHexString(const ql_byte_t* const valbytes, ql_byte_t* const str, const ql_size_t vallen, const ql_size_t strsize) {
    if(valbytes == NULL || str == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if(strsize < 2*vallen + 1){
        log_debug("strsize too small. strsize(%u) should >= vallen * 2 + 1(%d)\n", strsize, 2*vallen + 1);
        return CONTRACT_ERR_PARAM_INVALID;
    }
    ql_uint32_t i = 0;
    ql_byte_t L = 0;
    ql_byte_t H = 0;
    //bytes to hex string
    for(i = 0; i < vallen; i++) {
        H = (valbytes[i] >> 4) & 0x0f;
        L = (valbytes[i] & 0x0f);
        str[i*2]     = H < 10 ? H + '0' : H - 10 + 'a';
        str[i*2 + 1] = L < 10 ? L + '0' : L - 10 + 'a';
    }
    //end of string
    str[2*vallen] = 0;
    return CONTRACT_SUCCESS;
}

static contract_err_t encodeInt64To64Str(const ql_int64_t intval, ql_byte_t* const res, const ql_size_t ressize) {
    if(res == NULL || ressize < ARG_HEXSTRING_LEN + 1)return CONTRACT_ERR_PARAM_INVALID;
    ql_byte_t temp[ARG_NUMERIC_LEN];
    //sign
    ql_byte_t sig = intval < 0 ? 0xff : 0x00;
    // ql_uint32_t i = 0;
    ql_uint32_t j = 0;
    ql_size_t valsize = sizeof(intval);
    ql_int64_t localint = intval;

    for(j = 0; j < valsize; j++) {
        temp[ARG_NUMERIC_LEN-1 -j] = localint & 0xff;
        localint >>= 8;
    }
    for(j = 0; j < ARG_NUMERIC_LEN - valsize; j++) {//add sign
        temp[j] = sig;
    }
    //bytes to hex string
    return bytesToHexString(temp, res, ARG_NUMERIC_LEN, ressize);
}


static contract_err_t encodeUint64To64Str(ql_uint64_t uintval, ql_byte_t* const res, ql_size_t ressize) {
    if(res == NULL || ressize < ARG_HEXSTRING_LEN + 1)return CONTRACT_ERR_PARAM_INVALID;
    ql_byte_t temp[ARG_NUMERIC_LEN];
    ql_uint32_t i = 0;
    ql_size_t valsize = sizeof(uintval);
    //hex format
    for(i = 0; i < valsize; i++) {
        temp[ARG_NUMERIC_LEN-1 - i] = uintval & 0xff;
        uintval >>= 8;
    }
    for(i = 0; i < ARG_NUMERIC_LEN - valsize; i++)temp[i] = 0x00;
    //bytes to hex string
    return bytesToHexString(temp, res, ARG_NUMERIC_LEN, ressize);
}

static contract_err_t encodeUint32To64Str(ql_uint32_t uintval, ql_byte_t* const res, ql_size_t ressize) {
    if(res == NULL || ressize < ARG_HEXSTRING_LEN + 1)return CONTRACT_ERR_PARAM_INVALID;
    return encodeUint64To64Str((ql_uint64_t)uintval, res, ressize);
}



static contract_err_t addArg(arg_t* const args, arg_t* const addarg) {
    if(args == NULL || addarg == NULL)return CONTRACT_ERR_PARAM_INVALID;
    arg_t* argptr = args;
    ql_size_t arglen = 0;
    while(argptr->next)argptr = argptr->next, arglen++;
    argptr->next = addarg;
    args->len = arglen + 1;
    free(addarg);
    return CONTRACT_SUCCESS;
}

//Pass in val, length len.  It is eventually converted to hexadecimal string storage, even if it is originally STR, because only characters 0-f end up 
//Note that 64 alignment is not needed for the sake of calculating bytes or string lengths in dynamic types  
contract_err_t AddBytesArg(arg_t* const args, ql_byte_t* val, ql_size_t len) {
    if(args == NULL || val == NULL ) {
        return CONTRACT_ERR_PARAM_INVALID;
    }
    //alloc mem
    arg_t* temp = (arg_t*)malloc(sizeof(arg_t));
    temp->len = len * 2;
    temp->next = NULL;
    temp->val = (ql_byte_t*)calloc(len*2 + 1, sizeof(ql_byte_t));
    if(temp->val == NULL){
        ArgFree(temp);
        return CONTRACT_ERR_ALLOC_MEMORY;
    }
    // bytes to hex string
    contract_err_t ret = bytesToHexString(val, temp->val, len, len * 2 + 1);//bytes to hex string
    if(ret != CONTRACT_SUCCESS){
        ArgFree(temp);//free
        return ret;
    }
    return addArg(args, temp);
}

//size = sizeof(val[0])
contract_err_t AddUnsignedArrayArg(arg_t* const args, ql_void_t* val, ql_size_t arraylen, ql_size_t size) {
    if(args == NULL || val == NULL /*|| size % 8 != 0*/)return CONTRACT_ERR_PARAM_INVALID;
    //alloc mem and init 
    arg_t *temp = (arg_t*)malloc(sizeof(arg_t));
    if(temp == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
    temp->len = arraylen * ARG_HEXSTRING_LEN;
    temp->val = (ql_byte_t*)calloc(temp->len + 1, sizeof(ql_byte_t));
    temp->next = NULL;
    if(temp->val == NULL) {
        ArgFree(temp);
        return CONTRACT_ERR_ALLOC_MEMORY;
    }
    //different size means different type
    ql_uint32_t i = 0;
    contract_err_t ret;
    for(i = 0; i < arraylen; i++) {
        ql_uint64_t x = 0;
        switch (size)
        {
        case sizeof(ql_uint8_t):
            x = *((ql_uint8_t*)val + i);
            break;
        case sizeof(ql_uint16_t):
            x = *((ql_uint16_t*)val + i);
            break;
        case sizeof(ql_uint32_t):
            x = *((ql_uint32_t*)val + i);
            break;
        case sizeof(ql_uint64_t):
            x = *((ql_uint64_t*)val + i);
            break;
        default:
            ArgFree(temp);
            return CONTRACT_ERR_PARAM_INVALID;
        }
        ret = encodeUint64To64Str(x, &(temp->val[ARG_HEXSTRING_LEN * i]), ARG_HEXSTRING_LEN + 1);
        if(ret != CONTRACT_SUCCESS) {
            ArgFree(temp);
            return ret;
        }
    }
    return addArg(args, temp);
}

//size = sizeof(val[0])
contract_err_t AddSignedArrayArg(arg_t* const args, ql_void_t* val, ql_size_t arraylen, ql_size_t size) {
    if(args == NULL || val == NULL)return CONTRACT_ERR_PARAM_INVALID;
    arg_t *temp = (arg_t*)malloc(sizeof(arg_t));
    if(temp == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
    temp->len = arraylen * ARG_HEXSTRING_LEN;
    temp->val = (ql_byte_t*)calloc(temp->len + 1, sizeof(ql_byte_t));
    temp->next = NULL;
    if(temp->val == NULL) {
        ArgFree(temp);
        return CONTRACT_ERR_ALLOC_MEMORY;
    }
    ql_uint32_t i = 0;
    contract_err_t ret;
    for(i = 0; i < arraylen; i++) {
        ql_int64_t x = 0;
        switch (size)
        {
        case sizeof(ql_int8_t):
            x = *((ql_int8_t*)val + i);
            break;
        case sizeof(ql_int16_t):
            x = *((ql_int16_t*)val + i);
            break;
        case sizeof(ql_int32_t):
            x = *((ql_int32_t*)val + i);
            break;
        case sizeof(ql_int64_t):
            x = *((ql_int64_t*)val + i);
            break;
        default:
            ArgFree(temp);
            return CONTRACT_ERR_PARAM_INVALID;
        }
        ret = encodeInt64To64Str(x, &(temp->val[ARG_HEXSTRING_LEN * i]), ARG_HEXSTRING_LEN + 1);
        if(ret != CONTRACT_SUCCESS) {
            ArgFree(temp);
            return ret;
        }
    }
    return addArg(args, temp);
}

contract_err_t AddIntArg(arg_t* const args, ql_int64_t val) {
    if(args == NULL)return CONTRACT_ERR_PARAM_INVALID;
    //alloc mem
    arg_t *temp = (arg_t*)malloc(sizeof(arg_t));
    if(temp == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
    temp->len = ARG_HEXSTRING_LEN;
    temp->next = NULL;
    //number to hex string
    temp->val = (ql_byte_t*)calloc(ARG_HEXSTRING_LEN + 1, sizeof(ql_byte_t));
    if(temp->val == NULL){
        ArgFree(temp);
        return CONTRACT_ERR_ALLOC_MEMORY;
    }
    contract_err_t ret = encodeInt64To64Str(val, temp->val, ARG_HEXSTRING_LEN + 1);
    if(ret != CONTRACT_SUCCESS){
	    ArgFree(temp);
	    return ret;
    }
    return addArg(args, temp);
}

contract_err_t AddUintArg(arg_t* const args, ql_uint64_t val) {
    if(args == NULL)return CONTRACT_ERR_PARAM_INVALID;
    arg_t* temp = (arg_t*)malloc(sizeof(arg_t));
    if(temp == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
    temp->len = ARG_HEXSTRING_LEN;
    temp->next = NULL;
    temp->val = (ql_byte_t*)calloc(ARG_HEXSTRING_LEN + 1, sizeof(ql_byte_t));
    if(temp->val == NULL){
        ArgFree(temp);
        return CONTRACT_ERR_ALLOC_MEMORY;
    }
    contract_err_t ret = encodeUint64To64Str(val, temp->val, ARG_HEXSTRING_LEN + 1);
    if(ret != CONTRACT_SUCCESS){
    	ArgFree(temp);
	return ret;
    }
    return addArg(args, temp);
}


//Originally aligned with 32bytes, converted to a string, 1byte hexadecimal digits are represented by 2bytes characters, so strings should be aligned with 64bytes
static contract_err_t StrbytesAlign64(arg_t* const arg) {
    if(arg == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if(arg->len % 64 == 0)return CONTRACT_SUCCESS;
    ql_size_t oldlen = arg->len;
    ql_uint32_t i = 0;
    arg->len = (oldlen/64 + 1 ) * 64;

    //Use buf to store intermediate results
    ql_byte_t buf[arg->len + 1];
    for(i = 0; i < oldlen; i++)buf[i] = arg->val[i];
    for(i = oldlen; i < arg->len; i++)buf[i] = '0';
    buf[arg->len] = 0;//end of string
    free(arg->val);
    arg->val = (ql_byte_t*)calloc(arg->len + 1, sizeof(ql_byte_t));
    if(arg->val == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
    memcpy(arg->val, buf, arg->len + 1);

    return CONTRACT_SUCCESS;
}



//Format the contract, then hash it, then digitally sign it. Keccak256 and ECC are used
//reference account.c。
contract_err_t SetSignature(contract_t* const con, account_t acc) {
    if(con == NULL)return CONTRACT_ERR_PARAM_INVALID;
    ql_byte_t *hash_prefix = (ql_byte_t*)"from=%s"
    "&to=%s&value=0x%x&payload=0x%s&timestamp=%#llx"
    "&nonce=%#llx&opcode=%x&extra=%s&vmtype=%s"
    "&version=%s&extraid=%s&cname=%s";

    ql_size_t format_size = strlen(hash_prefix);
    ql_size_t con_size = strnlen((char*)con->from, 43) + strnlen((char*)con->to, 43) + sizeof(con->value)*8 +
        + sizeof(con->timestamp)*8 + sizeof(con->nonce)*8 + sizeof(OPCODE_TYPE)*8 +
        (con->extra?strlen((char*)con->extra):1) + sizeof(VM_TYPE)*8 + (con->version?strlen((char*)con->version):1) + 
        (con->extraid?strlen((char*)con->extraid):1) + (con->contractname?strlen((char*)con->contractname):1);//except payload
    
    if(format_size + con_size > MAX_BUF_LEN) {//except payload
        free(hash_prefix);
        return CONTRACT_ERR_OVER_MAX_SIZE;
    }
    ql_size_t payload_len = con->payload ? strlen(con->payload) : 0;
    ql_byte_t buffer[MAX_BUF_LEN + payload_len];
    //Notice the NULL part in the structure
    sprintf((char*)buffer, (char*)hash_prefix,
    con->from, con->to, con->value, (con->payload?con->payload:""), con->timestamp,con->nonce, con->opcode, 
    (con->extra?con->extra:""), con->vmtype==EVM? "EVM" :(con->vmtype==HVM? "HVM" : "BVM"), 
    (con->version?con->version:""), (con->extraid?con->extraid:""), (con->contractname?con->contractname:""));
//hash
    ql_byte_t data_hash[32];
    ql_byte_t *hash_ptr = data_hash;
    keccak256(buffer, strlen((char*)buffer), &hash_ptr);
    printKeccakData(data_hash);
//sign
    ql_byte_t sig[65];
    ql_err_t ret = uEccSign(acc.prikey, data_hash, sig);
    if(ret != ECC_SUCCESS) {
        log_error("contract sign failed: %d", ret);
        return ret;
    }
//to hex
    ql_size_t i;
    for(i = 0; i < 65; i++){
        con->signature[(i+1)*2] = ((sig[i]>>4) & 0x0f) <= 9 ? 
                                  ((sig[i]>>4) & 0x0f) + '0' : ((sig[i]>>4) & 0x0f) - 10 + 'a';
        con->signature[(i+1)*2 + 1] = (sig[i] & 0x0f) <= 9 ?
                                      (sig[i] & 0x0f) + '0' : (sig[i] & 0x0f) - 10 + 'a';
    }
    con->signature[0] = '0';
    con->signature[1] = '0';
    con->signature[132] = 0;
    log_info("sig: %s", con->signature);

    return CONTRACT_SUCCESS;
}

//copy content in src to dst
static void paramCopy(param_t* const dst, param_t* const src) {
    if(dst == NULL || src == NULL)return;
    dst->name = src->name;
    dst->components = src->components;
    memcpy(dst->indexed, src->indexed, sizeof(src->indexed));
    dst->paramType = src->paramType;
    dst->next = src->next;
}

static ql_size_t getParamSize(param_t* paramroot) {
    ql_size_t res = 0;
    while(paramroot){
        res++;
        paramroot = paramroot->next;
    }
    return res;
}

static PARAM_TYPE isdynamic(ql_byte_t* const type) {
    PARAM_TYPE res;
    if(strcmp(type, "bytes") == 0) {
        res = ABI_DYNAMIC;
    }else if(strcmp(type, "string") == 0) {
        res = ABI_DYNAMIC;
    }else if(strstr(type, "[]") != NULL) {
        res = ABI_DYNAMIC;
    }else {
        res = ABI_STATIC;
    }
    return res;
}

//Calculate the size of the bytes occupied, if the dynamic type t[], only the size of the bytes occupied by the basic type t
static ql_size_t cntBasicSize(ql_byte_t* const type) {
    if(type == NULL)return 0;
    if(!strcmp(type, "string") || !strcmp(type, "bytes"))return 1;
    return 32;
}

//Find the parameter structure for methodName. MethodName has no parameter list
static contract_err_t getFuncInputWithoutType(abi_t* const abiroot, ql_byte_t* const methodName, param_t*const res) {
    //check param
    if(abiroot == NULL || methodName == NULL || res == NULL)return CONTRACT_ERR_PARAM_INVALID;
    abi_t dstAbi;
    dstAbi.name = NULL;
    dstAbi.inputs = NULL;
    dstAbi.outputs = NULL;
    dstAbi.next = NULL;
    contract_err_t err = getFuncWithoutType(abiroot, methodName, &dstAbi);
    if(err != CONTRACT_SUCCESS) return err;
    paramCopy(res, dstAbi.inputs);
    return CONTRACT_SUCCESS;
}

//copy content in src to dst
static void copyAbi(abi_t* dst, abi_t* src) {
    dst->type = src->type;
    dst->name = src->name;
    dst->inputs = src->inputs;
    dst->outputs = src->outputs;
    memcpy(dst->payable, src->payable, sizeof(src->payable));
    memcpy(dst->stateMutability, src->stateMutability, sizeof(src->stateMutability));
    memcpy(dst->constant, src->constant, sizeof(src->constant));
    memcpy(dst->anonymous, src->anonymous, sizeof(src->anonymous));
    dst->next = src->next;
}

static contract_err_t getFuncWithoutType(abi_t* const abiroot, ql_byte_t* const methodName, abi_t*const res) {
    if(abiroot == NULL || methodName == NULL || res == NULL)return CONTRACT_ERR_PARAM_INVALID;
    abi_t* abiptr = abiroot;
    while(abiptr) {
        if(abiptr->name && !strcmp(abiptr->name, methodName)) {//find methodName
            copyAbi(res, abiptr);
            break;
        }
        abiptr = abiptr->next;
    }
    if(abiptr == NULL) {//didn't find 
        log_debug("method %s not found\n", methodName);
        return CONTRACT_ERR_PARAM_INVALID;
    }
    abiptr = abiptr->next;
    while(abiptr){//check if there is more than one function has the same name
        if(abiptr->name && !strcmp(abiptr->name, methodName)) {
            log_debug("more than one methodname:%s\n", methodName);
            return CONTRACT_ERR_PARAM_INVALID;
        }
        abiptr = abiptr->next;
    }
    return CONTRACT_SUCCESS;
}

//Get all the information for methodName
contract_err_t GetFunc(abi_t* const abiroot, ql_byte_t* const methodName, abi_t* const res) {
    if(abiroot == NULL || methodName == NULL || res == NULL)return CONTRACT_ERR_PARAM_INVALID;
    //If methodName doesn't have an argument list
    if(strstr(methodName, "(") == NULL) {
        return getFuncWithoutType(abiroot, methodName, res);
    } else if(strstr(methodName, ")") == NULL)return CONTRACT_ERR_PARAM_INVALID;
    //If methodName has a list of parameters
    //1.Handle methodName, get param 
    ql_byte_t method[strlen(methodName)];
    ql_uint32_t i = 0;
    while(methodName[i] != '(')method[i] = methodName[i], i++;//Copy the first part of methodName to method
    method[i] = 0;//end of string
    ql_uint32_t paramsize = 0; //Number of parameters
    ql_uint32_t paramMaxLen = 0;//Estimate the maximum length of the parameter type
    ql_uint32_t cnt = 0;//Auxiliary calculation parameter type length
    while(methodName[i]) {//Count the number of type lists
        cnt++;
        if(methodName[i] == ',' || methodName[i] == ')') {//means a param end
            if(methodName[i-1] != '(')paramsize++;//in case no param
            if(paramMaxLen < cnt)paramMaxLen = cnt;
            cnt = 0;
        }
        i++;
    }
    ql_byte_t param[paramsize][paramMaxLen+1];//store type
    memset(param, 0, sizeof(param));
    i = 0;
    while(methodName[i] != '(')i++;//meet（
    //get type information
    for(cnt = 0; cnt < paramsize; cnt++) {
        ql_uint32_t j = 0;
        while(methodName[i] && (methodName[i] == ',' || methodName[i] == '('))i++;
        while(methodName[i] && methodName[i] != ',' && methodName[i] != ')')param[cnt][j++] = methodName[i++];
        param[cnt][j] = 0;
    }

    //2.campare
    abi_t* abiptr = abiroot;
    ql_byte_t matched = 0;//Whether a match is made (in case there are no arguments)
    //visit all abi
    while(abiptr) {
        //If the names are the same and the number of arguments is the same, start comparing types
        if(abiptr->name && !strcmp(abiptr->name, method) && getParamSize(abiptr->inputs) == paramsize) {
            matched = 1;//Let's say it matches, even if there are no arguments, because we have the same number of arguments, it matches
            param_t* paramptr = abiptr->inputs;
            i = 0;
            while(paramptr) {//visit list of inputs
                if(paramptr->paramType == NULL)return CONTRACT_ERR_PARAM_INVALID;
                if(strcmp(paramptr->paramType, param[i]) != 0) {//not matched
                    matched = 0;
                    break;
                }
                i++;
                paramptr = paramptr->next;
            }
            if(matched == 1) {//matched
                break;
            }
        }
        abiptr = abiptr->next;
    }
    //if matched
    if(matched == 1) {
        copyAbi(res, abiptr);
        return CONTRACT_SUCCESS;
    }
    return CONTRACT_ERR_PARAM_INVALID;//not matched
}

//Find the parameter list for methodName. Whether or not methodName has an argument list
contract_err_t GetFuncInput(abi_t* const abiroot, ql_byte_t* const methodName, param_t* const res) {
    if(abiroot == NULL || methodName == NULL || res == NULL)return CONTRACT_ERR_PARAM_INVALID;
    //If methodName doesn't have an argument list
    if(strstr(methodName, "(") == NULL)return getFuncInputWithoutType(abiroot, methodName, res);
    abi_t dstAbi;
    dstAbi.name = NULL;
    dstAbi.inputs = NULL;
    dstAbi.outputs = NULL;
    dstAbi.next = NULL;
    contract_err_t err = GetFunc(abiroot, methodName, &dstAbi);
    if(err != CONTRACT_SUCCESS)return err;
    paramCopy(res, dstAbi.inputs);
    return CONTRACT_SUCCESS;
}

contract_err_t GetFuncOutput(abi_t* abiroot, ql_byte_t* methodName, param_t* res) {
    if(abiroot == NULL || methodName == NULL || res == NULL)return CONTRACT_ERR_PARAM_INVALID;
    abi_t dstAbi;
    dstAbi.name = NULL;
    dstAbi.inputs = NULL;
    dstAbi.outputs = NULL;
    dstAbi.next = NULL;
    contract_err_t err = GetFunc(abiroot, methodName, &dstAbi);
    if(err != CONTRACT_SUCCESS)return err;
    paramCopy(res, dstAbi.outputs);
    return CONTRACT_SUCCESS;
}

//Replace all intk for methodName with int256, where k is some number. MethodName comes with a list of parameters
static contract_err_t methodNormalize(const ql_byte_t* const methodName, ql_byte_t* const res, ql_size_t const ressize) {
    if(methodName == NULL || res == NULL)return CONTRACT_ERR_PARAM_INVALID;
    ql_byte_t buf[strlen(methodName) * 2];//Hold the result value temporarily
    ql_byte_t *ptr = NULL;//Records the first address of the "int" substring found
    ql_byte_t *bufptr = buf;//Record where the BUF is written
    ql_byte_t *methodptr = methodName;//记Record where methodName is currently read
    while(*methodptr != '(') {//copy until '('
        *bufptr++ = *methodptr++;
    }
    //if methodName = "***int8***"
    while( *methodptr!= ')' && (ptr = strstr(methodptr, "int")) != NULL) {//search "int"，ptr points to int8***
        while(methodptr < ptr + 3) {//copy methodName ***int
            *bufptr++ = *methodptr++;
        }
        //now in buf is ***int
        while(*methodptr >= '0' && *methodptr <= '9')methodptr++;
        *bufptr++ = '2';
        *bufptr++ = '5';
        *bufptr++ = '6';
        //now in buf is ***int256
    }
    //no "int" now, copy the rest string
    while(*methodptr) {
        *bufptr++ = *methodptr++;
    }
    *bufptr++ = 0;//end of string
    //Now buf is the finished formatted methodName.
    if(ressize <= strlen(buf)) {
        log_debug("res size too small\n");
        return CONTRACT_ERR_PARAM_INVALID;
    }
    memcpy(res, buf, strlen(buf) + 1);//include end of string
    return CONTRACT_SUCCESS;
}

// Hash the function selector. The format for methodName is funcName (Type1,type2...) Or without a list of types
// Param can be NULL
static contract_err_t encodeFuncSelector(const ql_byte_t* const methodName, const param_t* const param, arg_t* const encoderes) {
    if(methodName == NULL || encoderes == NULL) return CONTRACT_ERR_PARAM_INVALID;
    //Initialize the resulting structure
    encoderes->next = NULL;
    encoderes->len = 0;
    encoderes->val = NULL;
    param_t * paramptr ;
    ql_byte_t *buf = NULL;//Stores the name of a function with a list of types
    //1.Check if it is a function name with a type. If it is a function name without a type list, give it a type
    if(strstr(methodName, "(") == NULL) {//If there is no type list
        //1.1 Estimate the length of typed function names
        ql_size_t nameLen = strlen(methodName) + 5;
        paramptr = param;
        while(paramptr) {//Calculate the approximate length of the typed function
            if(paramptr->paramType)nameLen += strlen(paramptr->paramType) + 1;//With a comma
            paramptr = paramptr->next;
        }
        //1.2 Allocate memory based on the estimated length
        buf = (ql_byte_t*)calloc(nameLen, sizeof(ql_byte_t));
        if(buf == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
        //1.3 Start writing the function name with the type list in buf
        //1.3.1 the function name
        memcpy(buf, methodName, strlen(methodName));
        //1.3.2 left parenthesis
        strcat(buf, "(");
        paramptr = param;
        while(paramptr) {
            if(paramptr->paramType) {
                //1.3.Three types of
                strcat(buf, paramptr->paramType);
                //1.3.4 a comma
                if(paramptr->next != NULL)strcat(buf, ",");//"," if there's a type after it.
            }
            paramptr = paramptr->next;
        }
        //1.3.5 right parenthesis
        strcat(buf, ")");
    } else {//Otherwise, the type list is brought
        buf = (ql_byte_t*)calloc(strlen(methodName) + 1, sizeof(ql_byte_t));
        if(buf == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
        memcpy(buf, methodName, strlen(methodName) + 1);
    }
    //2.Normalize the function names
    ql_size_t SHAsize = strlen(buf) * 2;
    ql_byte_t needSHA[SHAsize];
    memset(needSHA, 0, sizeof(needSHA));
    contract_err_t ret = methodNormalize(buf, needSHA, SHAsize);
    free(buf);
    if(ret != CONTRACT_SUCCESS)return ret;

    //3.Use SHA for standardized function names
    // Keccak256 Use reference Account
    ql_byte_t *hashres = (ql_byte_t*)calloc(32, sizeof(ql_byte_t));
    if(hashres == NULL)return CONTRACT_ERR_ALLOC_MEMORY;
    keccak256(needSHA, strlen(needSHA), &hashres);
    
    //4.Sha results in a string
    encoderes->val = (ql_byte_t*)calloc(4*2 + 1, sizeof(ql_byte_t));
    if(encoderes->val == NULL) {
        free(hashres);
        free(encoderes->val);
        encoderes->val = NULL;
        return CONTRACT_ERR_ALLOC_MEMORY;
    }
    encoderes->len = 4*2;
    hashres[4] = 0;//Truncate the encoding result by intercepting the first four bytes
    ret = bytesToHexString(hashres, encoderes->val, 4, 4*2 + 1);
    free(hashres);
    if(ret != CONTRACT_SUCCESS) {
        free(encoderes->val);
        encoderes->val = NULL;
        return ret;
    }

    return CONTRACT_SUCCESS;
}

// Pass in the ABI structure, the function name, and return the result of encoding the function name into encoderes
//abiroot can be NULL when the function name has a type list
static contract_err_t encodeFunc(abi_t* const abiroot, ql_byte_t* const methodName, ql_strings_t* const encoderes) {
    if(methodName == NULL || encoderes == NULL)return CONTRACT_ERR_PARAM_INVALID;
    argInit(encoderes);
    if(strstr(methodName, "(") == NULL && abiroot == NULL)return CONTRACT_ERR_PARAM_INVALID;//There is neither type list nor ABI
    contract_err_t ret;
    param_t* methodParam = NULL;
    if(strstr(methodName, "(") == NULL){//If there is no type list
        methodParam = (param_t*)malloc(sizeof(param_t)); 
        ret = getFuncInputWithoutType(abiroot, methodName, methodParam);
        if(ret != CONTRACT_SUCCESS){
		free(methodParam);
		return ret;
	}
    }
    ret = encodeFuncSelector(methodName, methodParam, encoderes);
    if(methodParam != NULL)free(methodParam);
    return ret;
}

// Inputs args and encodeRes: inputs args and inputs
static contract_err_t encodearg(param_t *const inputs, arg_t* const args, ql_strings_t* const encodeRes) {
    //check param
    if(inputs == NULL || args == NULL || encodeRes == NULL)return CONTRACT_ERR_PARAM_INVALID;
    //Initializes a structure that stores encoded results
    argInit(encodeRes);
    //Checking the number of parameters
    if(args->len != getParamSize(inputs)) {
        log_debug("number of arguments not equal.arg:%u != param:%u\n", args->len, getParamSize(inputs));
        return CONTRACT_ERR_PARAM_INVALID;
    }
    //Calculates the number of dynamic and static parameter types
    ql_uint32_t staticSize = 0;//The size of bytes used to store static and dynamic parameters
    ql_uint32_t dynamicCnt = 0;//Number of dynamic types
    param_t *inputsptr = inputs;
    arg_t *argptr = args->next;
    //Traverse parameter
    while(inputsptr && argptr) {
        if(isdynamic(inputsptr->paramType) == ABI_DYNAMIC) {
            dynamicCnt++;
        }
        staticSize += 32;//32bytes. 32bytes for each store
        inputsptr = inputsptr->next;
        argptr = argptr->next;
    }
    //Encode the parameters
    ql_byte_t*  needMerge[dynamicCnt + args->len];//Each parameter corresponds to a hexadecimal string. Two dynamic parameters.
    ql_size_t   MergeLen[dynamicCnt + args->len]; //The number of bytes for each needMerge[I]
    argptr = args->next;//Points to the actual parameter because the parameter header node does not store parameter values
    inputsptr = inputs;
    ql_uint32_t dynamicPtr = staticSize;//The dynamic array is at the beginning of the ABI encoded result, which is 32*argSize. The corresponding position is computed in bytes
    ql_uint32_t curdynamic = 0;//The position of the dynamic array in the needMerge array
    ql_uint32_t i = 0;
    contract_err_t ret = CONTRACT_SUCCESS;
    //init needMerge
    for(i = 0; i < dynamicCnt + args->len; i++)needMerge[i] = NULL;
    i = 0;
    while(inputsptr && argptr) {
        if(isdynamic(inputsptr->paramType) == ABI_DYNAMIC) {//If it's dynamic
            //1.Store dynamicPtr, where dynamic types should be stored, in hexadecimal format to needMerge[i]
            needMerge[i] = (ql_byte_t*)calloc(ARG_HEXSTRING_LEN + 1, sizeof(ql_byte_t));
            if(needMerge[i] == NULL) {
                ret = CONTRACT_ERR_ALLOC_MEMORY;
                break;
            }
            MergeLen[i] = ARG_HEXSTRING_LEN;
            //Converts dynamic value positions to hexadecimal string format
            ret = encodeUint32To64Str(dynamicPtr, needMerge[i], ARG_HEXSTRING_LEN + 1);
            if(ret != CONTRACT_SUCCESS)break;
            //2.Store dynamic type parameter values in needMerge[curdynamic + args- > len]
            //2.0 Calculates the length of the dynamic type first
            ql_size_t basiclen = cntBasicSize(inputsptr->paramType);
            if(basiclen == 0) {
                log_debug("calculate dynamic type error\n");
                ret = CONTRACT_ERR_PARAM_INVALID;
                break;
            }
            ql_size_t dynamictypeLen = argptr->len / 2 / basiclen;//Dynamic type length

                //2.1Align 32bytes, that is, STR aligns 64bytes
            ret = StrbytesAlign64(argptr);
            if(ret != CONTRACT_SUCCESS)break;
                //2.2Put the dynamic data value into needMerge, and note whether the value contains length content.
            needMerge[curdynamic + args->len] = (ql_byte_t*)calloc(argptr->len + ARG_HEXSTRING_LEN + 1, sizeof(ql_byte_t));
            if(needMerge[curdynamic + args->len] == NULL) {
                ret =  CONTRACT_ERR_ALLOC_MEMORY;
                break;
            }
                    //2.2.1Encoding dynamic type length. Length is argptr->len / 2 bytes divided by the length of the type itself
            ret = encodeUint32To64Str(dynamictypeLen, needMerge[curdynamic + args->len], ARG_HEXSTRING_LEN + 1);
            if(ret != CONTRACT_SUCCESS)break;
            memcpy(&needMerge[curdynamic + args->len][ARG_HEXSTRING_LEN], argptr->val, argptr->len);//Copy the parameters to needMerge
            MergeLen[curdynamic + args->len] = argptr->len + ARG_HEXSTRING_LEN;//I'm also going to add 64 to the length calculation
            //3.Update where the next dynamic type parameter should be stored and in the ABI encoding format
            dynamicPtr += MergeLen[curdynamic + args->len];
            curdynamic++;
        }else {//Static type encoding. If it is
            //The alignment of 32
            contract_err_t ret = StrbytesAlign64(argptr);
            if(ret != CONTRACT_SUCCESS)break;
            //Assign a static type parameter
            needMerge[i] = (ql_byte_t*)calloc(argptr->len + 1, sizeof(ql_byte_t));
            if(needMerge[i] == NULL) {
                ret = CONTRACT_ERR_ALLOC_MEMORY;
                break;
            }
            MergeLen[i] = argptr->len;
            memcpy(needMerge[i], argptr->val, argptr->len);//Static type data is already aligned in addtyPearg before it is added
        }

        //Update the loop processing values until all parameters are processed
        inputsptr = inputsptr->next;
        argptr = argptr->next;
        i++;
    }
    if(ret != CONTRACT_SUCCESS) {
        for(i = 0; i < dynamicCnt + args->len; i++)free(needMerge[i]);
        return ret;
    }
    //Calculates the overall length of the encoding result
    for(i = 0; i < dynamicCnt + args->len; i++)encodeRes->len += MergeLen[i];

    //Merge all needMerge into a single entity
    encodeRes->val = (ql_byte_t*)calloc(encodeRes->len + 1, sizeof(ql_byte_t));
    ql_uint32_t copyptr = 0;
    for(i = 0; i < dynamicCnt + args->len; i++) {
        memcpy(&(encodeRes->val[copyptr]), needMerge[i], MergeLen[i]);
        copyptr += MergeLen[i];
        free(needMerge[i]);
    }
    return CONTRACT_SUCCESS;
}



//Parses the parameters from json format and stores them in a structure.
static contract_err_t paramFromJson(param_t* const param, cJSON *items) {
    if(param == NULL || items == NULL)return CONTRACT_ERR_PARAM_INVALID;
    param->name = NULL;
    param->paramType = NULL;
    param->components = NULL;
    param->indexed[0] = 0;
    param->next = NULL;
    cJSON *name = cJSON_GetObjectItem(items, "name");
    cJSON *type = cJSON_GetObjectItem(items, "type");
    cJSON *components = cJSON_GetObjectItem(items, "components");
    cJSON *indexed = cJSON_GetObjectItem(items, "indexed");
    if(name != NULL && name->valuestring != NULL) {
        ql_uint32_t len = strlen(name->valuestring);
        param->name = calloc(len+1, sizeof(ql_byte_t));
        memcpy(param->name, name->valuestring, len);
        param->name[len] = 0;
    }
    if(type != NULL && type->valuestring != NULL) {
        ql_uint32_t len = strlen(type->valuestring);
        param->paramType = calloc(len+1, sizeof(ql_byte_t));
        memcpy(param->paramType, type->valuestring, len);
        param->paramType[len] = 0;
    }
    if(components != NULL && components->valuestring != NULL) {
        ql_uint32_t len = strlen(components->valuestring);
        param->components = calloc(len+1, sizeof(ql_byte_t));
        memcpy(param->components, components->valuestring, len);
        param->components[len] = 0;
    }
    if(indexed != NULL && indexed->valueint != cJSON_NULL) {
        memset(param->indexed, 0, sizeof(param->indexed));
        if(indexed->valueint == cJSON_False){
            memcpy(param->indexed, "false", strlen("false"));
        }else if(indexed->valueint == cJSON_True){
            memcpy(param->indexed, "true", strlen("true"));
        }else {
            log_debug("param indexed invalid type\n");
            return CONTRACT_ERR_PARAM_INVALID;
        }
    }
    return CONTRACT_SUCCESS;
}

//Parsed in JSON format from abi related files, storing the information in the abiroot structure
static contract_err_t abiFromJson(abi_t* const abiroot, cJSON *items) {
    if(abiroot == NULL || items == NULL)return CONTRACT_ERR_PARAM_INVALID;
    contract_err_t ret = abiStructInit(abiroot);
    if(ret != CONTRACT_SUCCESS) return ret;
    //Traverse cJSON array
    ql_uint32_t item = 0;
    cJSON *object = NULL;
    abi_t *abicur = abiroot;
    abi_t *abipre = abiroot;
    for(item = 0; (object = cJSON_GetArrayItem(items, item)) != NULL; item++) {
        if(abicur == NULL){//In addition to root, create a new ABI structure
            abicur = (abi_t*)malloc(sizeof(abi_t));
            abiStructInit(abicur);
            abipre -> next = abicur;
        }
        //parse type
        cJSON *type = cJSON_GetObjectItem(object, "type");
        if(type == NULL || type->valuestring == NULL || !strcmp(type->valuestring, "function")) {
            abicur->type = ABI_FUNCTION;
        }else if(!strcmp(type->valuestring, "constructor")) {
            abicur->type = ABI_CONSTRUCTOR;
        }else if(!strcmp(type->valuestring, "fallback") || !strcmp(type->valuestring, "receive")) {
            abicur->type = ABI_FALLBACK;
        }else if(!strcmp(type->valuestring, "event")) {
            abicur->type = ABI_EVENT;
        }else {
            log_debug("abi type: invalid type\n");
            return CONTRACT_ERR_PARAM_INVALID;
        }
        //Parsing the anonymous
        cJSON *anonymous = cJSON_GetObjectItem(object, "anonymous");
        if(anonymous != NULL && anonymous->valueint != cJSON_NULL) {
            memset(abicur->anonymous, 0, sizeof(abicur->anonymous));
            if(anonymous->valueint == cJSON_True) {
                memcpy(abicur->anonymous, "true", strlen("true"));
            }else if(anonymous->valueint == cJSON_False) {
                memcpy(abicur->anonymous, "false", strlen("false"));
            }else {
                log_debug("abi anonymous invalid type\n");
                return CONTRACT_ERR_PARAM_INVALID;
            }
        }
        //constant
        cJSON *constant = cJSON_GetObjectItem(object, "constant");
        if(constant != NULL && constant->valueint != cJSON_NULL) {
            memset(abicur->constant, 0, sizeof(abicur->constant));
            if(constant->valueint == cJSON_True) {
                memcpy(abicur->constant, "true", strlen("true"));
            }else if(constant->valueint == cJSON_False) {
                memcpy(abicur->constant, "true", strlen("true"));
            }else {
                log_debug("abi constant invalid type\n");
                return CONTRACT_ERR_PARAM_INVALID;
            }
        }
        //name
        cJSON *name = cJSON_GetObjectItem(object, "name");
        if(name != NULL && name->valuestring != NULL) {
            ql_uint32_t len = strlen(name->valuestring);
            abicur->name = calloc(len + 1, sizeof(ql_byte_t));
            memcpy(abicur->name, name->valuestring, len);
            abicur->name[len] = 0;
        }
        //payable
        cJSON *payable = cJSON_GetObjectItem(object, "payable");
        if(payable != NULL && payable->valueint != cJSON_NULL) {
            memset(abicur->payable, 0, sizeof(abicur->payable));
            if(payable->valueint == cJSON_True) {
                memcpy(abicur->payable, "true", strlen("true"));
            }else if(payable->valueint == cJSON_False) {
                memcpy(abicur->payable, "false", strlen("false"));
            }else {
                log_debug("abi payable invalid type\n");
                return CONTRACT_ERR_PARAM_INVALID;
            }
        }
        //stateMUtability
        cJSON *stateMutability = cJSON_GetObjectItem(object, "stateMutability");
        if(stateMutability != NULL && stateMutability->valuestring != NULL) {
            if(!strcmp(stateMutability->valuestring, "pure") ||
            !strcmp(stateMutability->valuestring, "view") ||
            !strcmp(stateMutability->valuestring, "nonpayable") ||
            !strcmp(stateMutability->valuestring, "payable")) {
                memset(abicur->stateMutability, 0, sizeof(abicur->stateMutability));
                memcpy(abicur->stateMutability, stateMutability->valuestring, strlen(stateMutability->valuestring));
            }else {
                log_debug("abi stateMutability invalid type\n");
                return CONTRACT_ERR_PARAM_INVALID;
            }
        }
        //Inputs are exactly the order of their inputs
        cJSON *inputs = cJSON_GetObjectItem(object, "inputs");
        if(inputs != NULL && cJSON_GetArraySize(inputs) != 0) {
            abicur->inputs = (param_t*)malloc(sizeof(param_t));
            param_t *paramcur = abicur->inputs;
            param_t *parampre = paramcur;
            ql_uint32_t index = 0;
            cJSON *paramobj;
            //Traverse the inputs
            for(index = 0; (paramobj = cJSON_GetArrayItem(inputs, index)) != NULL; index++) {
                if(paramcur == NULL) {
                    paramcur = (param_t*)malloc(sizeof(param_t));
                    parampre->next = paramcur;
                }
                contract_err_t ret = paramFromJson(paramcur, paramobj);
                if(ret != CONTRACT_SUCCESS) {
                    return ret;
                }
                //Update the inputs linked list
                parampre = paramcur;
                paramcur = NULL;
            }
        }
        //output
        cJSON *outputs = cJSON_GetObjectItem(object, "outputs");
        if(outputs != NULL && cJSON_GetArraySize(outputs) != 0) {
            abicur->outputs = (param_t*)malloc(sizeof(param_t));
            param_t *paramcur = abicur->outputs;
            param_t *parampre = paramcur;
            ql_uint32_t index = 0;
            cJSON *paramobj;
            //Traverse the outputs
            for(index = 0; (paramobj = cJSON_GetArrayItem(outputs, index)) != NULL; index++) {
                if(paramcur == NULL) {
                    paramcur = (param_t*)malloc(sizeof(param_t));
                    parampre->next = paramcur;
                }
                contract_err_t ret = paramFromJson(paramcur, paramobj);
                if(ret != CONTRACT_SUCCESS) return ret;
                //Update the chain list where outputs are located
                parampre = paramcur;
                paramcur = NULL;
            }
        }

        //Update the linked list of ABI structures
        abipre = abicur;//Update abipre to Abicur
        abicur = NULL;
    }
    return CONTRACT_SUCCESS;
}

contract_err_t AbiInitFromString(abi_t* const abiroot, ql_byte_t *str) {
    if(abiroot == NULL || str == NULL)return CONTRACT_ERR_PARAM_INVALID;
    cJSON *items = cJSON_Parse((char*)str);
    if(items == NULL) {
        log_debug("parse json from string fail\n");
        return CONTRACT_ERR_PARAM_INVALID;
    }
    contract_err_t err = abiFromJson(abiroot, items);
    if(items != NULL) cJSON_Delete(items);
    return err;
}



//evm uses deploy and calls constructor. If abiroot is not NULL, the ABI structure stores abiroot. Otherwise, abiroot is not saved
//conpath is the contract content file, abipath is the ABI file, and args is the constructor parameter
contract_err_t DeployEvmWithParam(contract_t* const con, abi_t *abiroot, ql_byte_t *partOfpayLoad, arg_t *args) {
    if(con == NULL || abiroot == NULL || partOfpayLoad == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if( args == NULL) {//No arguments
        return DeployEvmWithoutParam(con, partOfpayLoad);
    }
    setTo(con, "\0");
    //Handles ABI constructs and abipath
    abi_t* abiptr = abiroot;
    //Find Constructor in the ABI structure
    abi_t *paramptr = abiptr;
    while(paramptr && paramptr->type != ABI_CONSTRUCTOR)paramptr = paramptr->next;
    if(paramptr == NULL) {
        log_debug("no constructor in this abi\n");
        return CONTRACT_ERR_PARAM_INVALID;
    }
    //Inputs in constructor and parameter information to get the parameter encoding
    arg_t *Argencode = (arg_t*)malloc(sizeof(arg_t));//Coding results
    Argencode->len = 0;
    Argencode->val = NULL;
    Argencode->next = NULL;
    contract_err_t ret = encodearg(paramptr->inputs, args, Argencode);
    if(ret != CONTRACT_SUCCESS) {
        ArgFree(Argencode);
        return ret;
    }
    //Get the contract content, and store it in the payload of the con
    ret = setPayload(con, partOfpayLoad);
    if(ret != CONTRACT_SUCCESS) {
        ArgFree(Argencode);
        return ret;
    }
    //The payload is the current content of the payload
    // don't need anything else
    ql_size_t oldlen = strlen((char*)con->payload);
    con->payload = (ql_byte_t*)realloc(con->payload, oldlen + Argencode->len + 1);
    memcpy(con->payload + oldlen, Argencode->val, Argencode->len);
    con->payload[oldlen + Argencode->len] = 0;//End of string
    ArgFree(Argencode);
    return CONTRACT_SUCCESS;
}

//Version below 3.0,EVM has no ABI, filepath is contract content
contract_err_t DeployEvmWithoutParam(contract_t* const con, ql_byte_t *payLoad) {
    if(con == NULL || payLoad == NULL)return CONTRACT_ERR_PARAM_INVALID;
    setTo(con, "\0");
    return setPayload(con, payLoad);
}

contract_err_t InvokeEVM(contract_t* const con, ql_byte_t* const conAddr, ql_byte_t* const methodName, abi_t* const abi, arg_t* const args) {
    if(con == NULL || conAddr == NULL || methodName == NULL || abi == NULL ) return CONTRACT_ERR_PARAM_INVALID;
    //0.Do some basic initialization for CON
    contract_err_t ret;
    //1.Set the contract call address
    ret = setTo(con, conAddr);
    if(ret != CONTRACT_SUCCESS)return ret;
    //2.Get the methodName parameter list
    param_t inputs;//Easy to free memory
    ret = GetFuncInput(abi, methodName, &inputs);
    if(ret != CONTRACT_SUCCESS)return ret;
    //3.So we encode methodName
    arg_t encodeFuncRes;
    ret = encodeFunc(abi, methodName, &encodeFuncRes);
    if(ret != CONTRACT_SUCCESS) {
        free(encodeFuncRes.val);
        return ret;
    }
    //4.If the argument is not NULL, encode is applied to the argument
    arg_t encodeArgRes;
    argInit(&encodeArgRes);
    if(args != NULL) {
        ret = encodearg(&inputs, args, &encodeArgRes);
        if(ret != CONTRACT_SUCCESS) {
            free(encodeFuncRes.val);
            free(encodeArgRes.val);
            return ret;
        }        
    }
    //5.Set the content
    ql_byte_t buf[encodeFuncRes.len + encodeArgRes.len + 1];
    memcpy(buf, encodeFuncRes.val, encodeFuncRes.len);
    memcpy(&buf[encodeFuncRes.len], encodeArgRes.val, encodeArgRes.len);
    buf[encodeFuncRes.len +encodeArgRes.len] = 0;//End of string character
    ret = setPayload(con, buf);

    free(encodeArgRes.val);
    free(encodeFuncRes.val);
    if(ret != CONTRACT_SUCCESS)return ret;

    return CONTRACT_SUCCESS;
}

//Update the contract. Payload is the contract you want to update
contract_err_t ConUpdate(contract_t* const con, ql_byte_t *conAddress, ql_byte_t *payload) {
    if(con == NULL || conAddress == NULL || payload == NULL) {
        return CONTRACT_ERR_PARAM_INVALID;
    }
    if(strnlen((char*)conAddress, 43) != 42)return CONTRACT_ERR_PARAM_INVALID;
    contract_err_t ret = setTo(con, conAddress);
    if(ret != CONTRACT_SUCCESS)return ret;
    con->opcode = QL_UPDATE;
    return setPayload(con, payload);
}

contract_err_t ConFreeze(contract_t* const con, ql_byte_t *conAddress) {
    if(con == NULL || conAddress == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if(strnlen((char*)conAddress, 43) != 42)return CONTRACT_ERR_PARAM_INVALID;
    contract_err_t ret = setTo(con, conAddress);
    if(ret != CONTRACT_SUCCESS)return ret;
    con->opcode = QL_FREEZE;
    return CONTRACT_SUCCESS;
}

contract_err_t ConUnfreeze(contract_t* const con, ql_byte_t *conAddress) {
    if(con == NULL || conAddress == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if(strnlen((char*)conAddress, 43) != 42)return CONTRACT_ERR_PARAM_INVALID;
    contract_err_t ret = setTo(con, conAddress);
    if(ret != CONTRACT_SUCCESS)return ret;
    con->opcode = QL_UNFREEZE;
    return CONTRACT_SUCCESS;
}

contract_err_t ConDestroy(contract_t* const con, ql_byte_t *conAddress) {
    if(con == NULL || conAddress == NULL)return CONTRACT_ERR_PARAM_INVALID;
    if(strnlen((char*)conAddress, 43) != 42)return CONTRACT_ERR_PARAM_INVALID;
    contract_err_t ret = setTo(con, conAddress);
    if(ret != CONTRACT_SUCCESS)return ret;
    con->opcode = QL_DESTROY;
    return CONTRACT_SUCCESS;
}



static void paramFree(param_t *param) {
    while(param) {
        param_t *now = param;
        param = param->next;
        if(now->name)free(now->name);
        if(now->paramType)free(now->paramType);
        if(now->components)free(now->components);
        free(now);
    }
}

void AbiFree(abi_t* abi) {
    while(abi) {
        abi_t *now = abi;
        abi = abi->next;
        if(now->name)free(now->name);
        paramFree(now->inputs);
        paramFree(now->outputs);
        free(now);
    }
}

void ArgFree(arg_t *arg) {
    while(arg) {
        if(arg->val)free(arg->val);
        arg_t *temp = arg;
        arg = arg->next;
        free(temp);
    }
}

//------------------------------------------------response------------------------------------------

void CleanReceipt(ReceiptResponse_t*const receipt) {
    freeLogs(receipt->log);
    free(receipt->ret);
    free(receipt->txHash);
    free(receipt->vmType);
    free(receipt->version);
    ReceiptInit(receipt);
}

static void freeTopics(void* ptr) {
    topic_t* topics = (topic_t*)ptr;
    topic_t* curtopic = topics;
    while(curtopic) {
        topics = curtopic->next;
        free(curtopic->val);
        free(curtopic);
        curtopic = topics;
    } 
}
//only free a log
static void freeLog(void* ptr) {
    eventlog_t* log = (eventlog_t*)ptr;
    if(log == NULL)return;
    if(log->topics != NULL)freeTopics(log->topics);
    log->topics = NULL;
    if(log->data != NULL)free(log->data);
    log->data = NULL;
    if(log->blockHash != NULL)free(log->blockHash);
    log->blockHash = NULL;
    if(log->txHash != NULL)free(log->txHash);
    log->txHash = NULL;
    log->next = NULL;
    free(log);
}

static void freeLogs(void* ptr) {
    eventlog_t* logs = (eventlog_t*)ptr;
    eventlog_t* curlog = logs;
    while(curlog) {
        logs = logs->next;
        freeLog(curlog);
        curlog = logs;
    }
}

static eventlog_t* createLog() {
    eventlog_t* ret = (eventlog_t*)calloc(1, sizeof(eventlog_t));
    if(ret == NULL)return NULL;
    ret->topics = NULL;
    ret->data = NULL;
    ret->blockHash = NULL;
    ret->txHash = NULL;
    ret->next = NULL;
    return ret;
}

static topic_t* createTopic() {
    topic_t* ret = (topic_t*)calloc(sizeof(topic_t), 1);
    if(ret == NULL){
	    return NULL;
    }
    ret->len = 0;
    ret->val = NULL;
    ret->next = NULL;
    return ret;
}



//Initialization, all become NULL
void ReceiptInit(ReceiptResponse_t * const receipt) {
    receipt->log = NULL;

    memset(receipt->conAddr, 0, sizeof(receipt->conAddr));
    receipt->ret = NULL;
    receipt->txHash = NULL;
    receipt->vmType = NULL;
    receipt->gasUsed = -1;
    receipt->version = NULL;
}

void cleanLog(eventlog_t* log) {
    freeTopics(log->topics);
    log->topics = NULL;
    free(log->data);
    log->data = NULL;
    free(log->blockHash);
    log->blockHash = NULL;
    free(log->txHash);
    log->txHash = NULL;
    freeLogs(log->next);
    log->next = NULL;
}

static response_err_t logFromJson(eventlog_t *const log, cJSON *items) {
    if(log == NULL)return RESPONSE_ERR_PARAM_INVALID;
    if(items == NULL) {//It doesn't have to be log
        log_debug("there is no log information.\n");
        return RESPONSE_SUCCESS;
    }
    eventlog_t *prev = log;
    eventlog_t *cur = log;
    ql_uint32_t i = 0;
    cJSON *item = NULL;
    response_err_t ret = RESPONSE_SUCCESS;
    for(i = 0; (item = cJSON_GetArrayItem(items, i)) != NULL; i++) {
        if(cur == NULL) {
            cur = createLog();
            if(cur == NULL) {
                ret = RESPONSE_ERR_ALLOC_MEM;
                break;
            }
            prev->next = cur;
        }
        cJSON *address = cJSON_GetObjectItem(item, "address");
        cJSON *topicarray = cJSON_GetObjectItem(item, "topics");
        cJSON *data = cJSON_GetObjectItem(item, "data");
        cJSON *blockNumber = cJSON_GetObjectItem(item, "blockNumber");
        cJSON *blockHash = cJSON_GetObjectItem(item, "blockHash");
        cJSON *txHash = cJSON_GetObjectItem(item, "txHash");
        cJSON *txIndex = cJSON_GetObjectItem(item, "txInedx");
        cJSON *index = cJSON_GetObjectItem(item, "index");
        //address string
        if(address != NULL && address->valuestring != NULL) {
            memcpy(cur->addr, address->valuestring, 42);
            cur->addr[42] = 0;
        }
        //topics string array
        ql_int32_t j = 0;
        cJSON *topics;
        if(topicarray != NULL && cur->topics == NULL) {
            cur->topics = createTopic();
            if(cur->topics == NULL) {
                ret = RESPONSE_ERR_ALLOC_MEM;
                break;
            }
        }
        topic_t* curtopic = cur->topics;
        topic_t* prevtopic = curtopic;
        for(j = 0; (topics = cJSON_GetArrayItem(topicarray, j)) != NULL; j++) {
            if(curtopic == NULL) {
                curtopic = createTopic();
                if(curtopic == NULL) {
                    ret = RESPONSE_ERR_ALLOC_MEM;
                    break;
                }
                prevtopic->next = curtopic;
            }
            //get one topics value
            if(topics->valuestring != NULL) {
                curtopic->val = StrMalloc(topics->valuestring, strlen(topics->valuestring));
                if(curtopic->val == NULL) {
                    ret = RESPONSE_ERR_ALLOC_MEM;
                    break;
                }
                curtopic->len = strlen(curtopic->val);
            }
            prevtopic = curtopic;
            curtopic = NULL;
        }
        if(ret != RESPONSE_SUCCESS)break;
        //data
        if(data != NULL && data->valuestring != NULL) {
            cur->data = StrMalloc(data->valuestring, strlen(data->valuestring));
        }
        //blockNumber
        if(blockNumber != NULL)cur->blockNumber = blockNumber->valueint;
        //blockHash
        if(blockHash != NULL && blockHash->valuestring != NULL) {
            cur->blockHash = StrMalloc(blockHash->valuestring, strlen(blockHash->valuestring));
        }
        //txHash
        if(txHash != NULL && txHash->valuestring != NULL) {
            cur->txHash = StrMalloc(txHash->valuestring, strlen(txHash->valuestring));
        }
        //txIndex
        if(txIndex != NULL)cur->txIndex = txIndex->valueint;
        //index
        if(index != NULL)cur->index = index->valueint;

        //update prev and cur
        prev = cur;
        cur = NULL;
    }
    if(ret != RESPONSE_SUCCESS) {
        cleanLog(log);
        return ret;
    }
    return RESPONSE_SUCCESS;
}

response_err_t ReceiptFromJson(ReceiptResponse_t *const receipt, cJSON *result) {
    if(receipt == NULL || result == NULL)return RESPONSE_ERR_PARAM_INVALID;
    ReceiptInit(receipt);

    cJSON *log = cJSON_GetObjectItem(result, "log");
    
    if(result == NULL)return RESPONSE_ERR_PARAM_INVALID;

    cJSON *conAddr = cJSON_GetObjectItem(result, "contractAddress");
    cJSON *ret = cJSON_GetObjectItem(result, "ret");
    cJSON *txHash = cJSON_GetObjectItem(result, "txHash");
    cJSON *vmType = cJSON_GetObjectItem(result, "vmType");
    cJSON *gasUsed = cJSON_GetObjectItem(result, "gasUsed");
    cJSON *version = cJSON_GetObjectItem(result, "version");
    //log
    if(log != NULL && cJSON_GetArraySize(log) > 0) {
        receipt->log = createLog();
        logFromJson(receipt->log, log);
    } 
    //conAddr
    if(conAddr != NULL && conAddr->valuestring != NULL) {
        memcpy(receipt->conAddr, conAddr->valuestring, 42);
        receipt->conAddr[42] = 0;
    }
    //ret
    if(ret != NULL && ret->valuestring != NULL) {
        receipt->ret = StrMalloc(ret->valuestring, strlen(ret->valuestring));
    }
    //txHash
    if(txHash != NULL && txHash->valuestring != NULL) {
        receipt->txHash = StrMalloc(txHash->valuestring, strlen(txHash->valuestring));
    }
    //vmType
    if(vmType != NULL && vmType->valuestring != NULL) {
        receipt->vmType = StrMalloc(vmType->valuestring, strlen(vmType->valuestring));
    }
    //gasUsed
    if(gasUsed != NULL)receipt->gasUsed = gasUsed->valueint;
    //version
    if(version != NULL && version->valuestring != NULL) {
        receipt->version = StrMalloc(version->valuestring, strlen(version->valuestring));
    }

    return RESPONSE_SUCCESS;
}


static response_err_t decode64HexStrToUint(const ql_byte_t* const str, ql_uint64_t* const retval) {
    if(str == NULL || retval == NULL)return RESPONSE_ERR_PARAM_INVALID;
    //Check whether the entered string length is less than 64. If the value is greater than 64, only the first 64 bits are judged
    if(strnlen(str, 65) < 64)return RESPONSE_ERR_PARAM_INVALID;
    ql_uint64_t ret = 0;
    ql_int32_t i = 0;
    ql_byte_t temp = 0;
    //Get rid of the leading zeros
    while(i < 64 && str[i] == '0')i++;
    //A character representing 0-f is four bits. Check whether retval can be saved or not
    if((64 - i) * 4 > sizeof(ql_uint64_t)*8 )return RESPONSE_ERR_OVERFLOW;
    //Convert hexadecimal strings to values for RET
    for(ret = 0; i < 64; i++) {
        if(str[i] >= '0' && str[i] <= '9')temp = str[i] - '0';
        else if(str[i] >= 'a' && str[i] <= 'f')temp = str[i] - 'a' + 10;
        else if(str[i] >= 'A' && str[i] <= 'F')temp = str[i] - 'A' + 10;
        else return RESPONSE_ERR_PARAM_INVALID;
        ret <<= 4;
        ret |= temp;
    }
    *retval = ret;
    return RESPONSE_SUCCESS;
}

// a 0-f character contains 4 bits
static response_err_t decode64HexStrToInt(const ql_byte_t* const str, ql_int64_t* const retval) {
    if(str == NULL || retval == NULL)return RESPONSE_ERR_PARAM_INVALID;
    if(strnlen(str, 65) < 64)return RESPONSE_ERR_PARAM_INVALID;
    ql_uint64_t ret = 0;
    ql_int32_t i = 0;
    // ql_byte_t temp = 0;
    response_err_t err = RESPONSE_SUCCESS;
    ql_byte_t localstr[64 + 1];
    memset(localstr, 0, sizeof(localstr));
    memcpy(localstr, str, 64);
    //Determine the positive and negative
    if(localstr[0] == '0') {
        err = decode64HexStrToUint(localstr, retval);
        if(err != RESPONSE_SUCCESS)return err;
    }else if(localstr[0] == 'f') {
        i = 0;
        while(i < 64 - sizeof(ql_int64_t)*8/4 && localstr[i] == 'f')localstr[i] = '0', i++;//Remove the leading 1,4bit one character
        if((64 - i) * 4 > sizeof(ql_int64_t)*8)return RESPONSE_ERR_OVERFLOW;
        //The leading 1 has been processed down to a 16-bit string. Check whether the remaining 16-bit string is negative or overflows if it is not
        if(localstr[i] < '8' && localstr[i] > '0')return RESPONSE_ERR_OVERFLOW;
        //- The leading 1 has been changed to 0 by unsigned string decoding (the result is 64-bit binary from the machine point of view, no sign)
        err = decode64HexStrToUint(localstr, &ret);
        if(err != RESPONSE_SUCCESS)return err;
        *retval = ret;
    } else RESPONSE_ERR_OVERFLOW;//It doesn't start with all 1s, either the arguments are wrong, or it overflows
    return RESPONSE_SUCCESS;
}

//Converts the strlen length of the hexadecimal format string STR to hexadecimal bytes numeric storage
static response_err_t decodeHexStrToBytes(ql_byte_t* const str, ql_byte_t* const ret, const ql_uint64_t strlen, const ql_uint64_t retsize) {
    if(str == NULL || ret == NULL)return RESPONSE_ERR_PARAM_INVALID;
    if(strlen%2 == 1)RESPONSE_ERR_PARAM_INVALID;
    if(strlen/2 + 1 > retsize)return RESPONSE_ERR_PARAM_INVALID;
    ql_uint64_t i = 0;
    for( i = 0; i < strlen; i++) {
        ql_byte_t temp = 0;
        if(str[i] >= '0' && str[i] <= '9')temp = str[i] - '0';
        else if(str[i] >= 'a' && str[i] <= 'f')temp = str[i] - 'a' + 10;
        else if(str[i] >= 'A' && str[i] <= 'F')temp = str[i] - 'A' + 10;
        else return RESPONSE_ERR_PARAM_INVALID;
        if(i & 0x01)ret[i >> 1] |= temp;//The odd digit is the lower four digits
        else ret[i >> 1] = temp << 4;//The even digit is the higher four digits  
    }
    ret[strlen/2] = 0;
    return RESPONSE_SUCCESS;
}

// static 
static response_err_t decode64HexStrsToUint64Array(const ql_byte_t* const str, const ql_size_t arraylen, ql_uint64_t*const res, const ql_size_t reslen) {
    if(str == NULL || res == NULL || reslen < arraylen)return RESPONSE_ERR_PARAM_INVALID;
    if(strnlen(str, arraylen*64) < arraylen*64)return RESPONSE_ERR_PARAM_INVALID;
    ql_size_t i = 0;
    for(i = 0; i < arraylen; i++) {
        response_err_t err = decode64HexStrToUint(str + 64*i, &res[i]);
        if(err != RESPONSE_SUCCESS)return err;
    }
    return RESPONSE_SUCCESS;
}

// static 
static response_err_t decode64HexStrsToInt64Array(const ql_byte_t* const str, const ql_size_t arraylen, ql_int64_t* const res, const ql_size_t reslen) {
    if(str == NULL || res == NULL || reslen < arraylen)return RESPONSE_ERR_PARAM_INVALID;
    if(strnlen(str, arraylen*64) < arraylen*64)return RESPONSE_ERR_PARAM_INVALID;
    ql_size_t i = 0;
    for(i = 0; i < arraylen; i++) {
        response_err_t err = decode64HexStrToInt(str + 64*i, &res[i]);
        if(err != RESPONSE_SUCCESS)return err;
    }
    return RESPONSE_SUCCESS;
}

static DECODE_BASICTYPE getDecodeType(const ql_byte_t* const type) {
    if(type == NULL)return NO_TYPE;
    //bytes
    if(strstr(type, "byte") != NULL)return DEC_BYTES;
    if(strstr(type, "string") != NULL)return DEC_STRING;
    if(strstr(type, "uint") != NULL || strstr(type, "bool") != NULL || strstr(type, "address") != NULL) {
        return UINT_VAL;
    }
    if(strstr(type, "int") != NULL )return INT_VAL;
    return NO_TYPE;
}

static ql_uint64_t StaticTypeLen(const ql_byte_t* const type) {
    if(type == NULL)return 0;
    ql_uint64_t size = 0;
    //T[n]
    if(strstr(type, "[") != NULL) {
        ql_int32_t i = 0;
        //unitl meet '['
        while(type[i] && type[i] != '[')i++;
        if(type[++i] == ']')return 0;
        for( ; type[i] && type[i] != ']'; i++) {
            if(type[i] > '9' || type[i] < '0')return 0;
            size = size*10 + type[i] - '0';
        }
        return size;
    }
    //bytesx where x <= 32
    if(strstr(type, "bytes") != NULL) {
        ql_int32_t i = 0;
        //filter what is not number
        while(type[i] && !(type[i] <= '9' && type[i] >= '0'))i++;
        if(type[i] == 0)return 1;//no number
        for(; type[i] && type[i] <= '9' && type[i] >= '0'; i++) {
            size = size*10 + type[i] - '0';
        }
        return size;
    }
    //other type 
    return 1;
}

// Decode from in
// If it is a number, it is originally a hexadecimal string (keep it 64 bits, if it is an array, n*64)
// Remove extra '0' for string and bytes
// To store the type and length information, because there is length information, do not store whether the array is a dynamic array
static response_err_t decodeFromParam(const param_t* const params, const ql_byte_t* const in, decode_t*const res) {
    if(in == NULL || strnlen(in, 1) == 0) {//No parameters, no decoding required
        log_debug("no ret.\n");
        return RESPONSE_SUCCESS;
    }
    if(res == NULL || params == NULL || in == NULL || strnlen(in, 1) == 0)return RESPONSE_ERR_PARAM_INVALID;
    ql_byte_t* ret = in;
    if(in[0] == '0' && in[1] == 'x')ret = in + 2;//0x+number
    decode_t* curdecode = res;//Currently points to the decoder structure
    decode_t* prevdecode = res;//Previous decoding structure
    param_t*  curparam = params;//Current parameter type information structure
    ql_byte_t* retp = ret;//Pointer to the current location of RET
    ql_byte_t* lastp = ret + strlen(ret);//Pointer boundary value
    response_err_t err = RESPONSE_SUCCESS;
    while(curparam) {
        //alloc curdecode mem
        if(curdecode == NULL) {
            curdecode = CreateDecodeT();
            if(curdecode == NULL) {
                err = RESPONSE_ERR_ALLOC_MEM;
                break;
            }
            prevdecode->next = curdecode;
        }
        //get basic type
        curdecode->type = getDecodeType(curparam->paramType);
        //If the parameter type is not identified
        if(curdecode->type == NO_TYPE) {
            err = RESPONSE_ERR_ALLOC_MEM;
            break;
        }
        //dynamic type
        if(isdynamic(curparam->paramType) == ABI_DYNAMIC) {
            //Calculates the location and length of the dynamic array
            ql_uint64_t pos = 0;
            ql_uint64_t paramlen = 0;
            err = decode64HexStrToUint(retp, &pos);
            //Failed to compute dynamic array position
            if(err != RESPONSE_SUCCESS) { 
                break;
            }
            //Dynamic array position pointer
            ql_byte_t* dynamicPos = ret + pos;
            //Dynamic array length fetch
            err = decode64HexStrToUint(dynamicPos, &paramlen);
            if(err != RESPONSE_SUCCESS) {
                break;
            }
            //First address of a dynamic array
            dynamicPos = dynamicPos + 64;
            //Cuts dynamicpos string by type
            if(curdecode->type == INT_VAL /*|| curdecode->type == UINT_VAL*/) {
                // int array
                curdecode->bytes = (ql_byte_t*)calloc(paramlen, sizeof(ql_int64_t));
                if(curdecode->bytes == NULL) {
                    err = RESPONSE_ERR_ALLOC_MEM;
                    break;
                }
                err = decode64HexStrsToInt64Array(dynamicPos, paramlen, (ql_int64_t*)curdecode->bytes, paramlen);
                if(err != RESPONSE_SUCCESS)break;
            }else if(curdecode->type == UINT_VAL) {
                //uint array
                curdecode->bytes = (ql_byte_t*)calloc(paramlen, sizeof(ql_int64_t));
                if(curdecode->bytes == NULL) {
                    err = RESPONSE_ERR_ALLOC_MEM;
                    break;
                }
                err = decode64HexStrsToUint64Array(dynamicPos, paramlen, (ql_uint64_t*)curdecode->bytes, paramlen);
                if(err != RESPONSE_SUCCESS) break;
            } else {//string or bytes
                ql_byte_t temp[paramlen + 1];
                memset(temp, 0, sizeof(temp));
                err = decodeHexStrToBytes(dynamicPos, temp, paramlen*2, sizeof(temp));
                if(err != RESPONSE_SUCCESS)break;
                curdecode->bytes = StrMalloc(temp, paramlen);
            }
            curdecode->len = paramlen;
            //update retp
            retp = retp + 64;
        } else { //static type
            //Compute the length, if it's an array, it's the array length, otherwise it's 1
            ql_uint64_t paramlen = StaticTypeLen(curparam->paramType);
            curdecode->len = paramlen;
            if(paramlen == 0) {
                err = RESPONSE_ERR_PARAM_INVALID;
                break;
            }
            //Slits the string by type
            if(curdecode->type == INT_VAL ) {
                curdecode->bytes = (ql_byte_t*)calloc(paramlen, sizeof(ql_int64_t));
                if(curdecode->bytes == NULL) {
                    err = RESPONSE_ERR_ALLOC_MEM;
                    break;
                }
                err = decode64HexStrsToInt64Array(retp, paramlen, curdecode->bytes, paramlen);
                if(err != RESPONSE_SUCCESS)break;
                //update retp
                retp = retp + paramlen * ARG_HEXSTRING_LEN;
            }else if(curdecode->type == UINT_VAL) {
                curdecode->bytes = (ql_byte_t*)calloc(paramlen, sizeof(ql_int64_t));
                if(curdecode->bytes == NULL) {
                    err = RESPONSE_ERR_ALLOC_MEM;
                    break;
                }
                err = decode64HexStrsToUint64Array(retp, paramlen, curdecode->bytes, paramlen);
                if(err != RESPONSE_SUCCESS)break;
                //update retp
                retp = retp + paramlen * ARG_HEXSTRING_LEN;
            }  else {//string or bytes
                ql_byte_t temp[paramlen + 1];
                memset(temp, 0, sizeof(temp));
                err = decodeHexStrToBytes(retp, temp, paramlen*2, sizeof(temp));
                if(err != RESPONSE_SUCCESS)break;
                curdecode->bytes = StrMalloc(temp, sizeof(temp));
                //update retp
                retp = retp + (paramlen % ARG_HEXSTRING_LEN == 0 ?
                        paramlen : (paramlen / ARG_HEXSTRING_LEN + 1) * ARG_HEXSTRING_LEN);
            }
        }
        //Determine whether reTP exceeds the boundary value
        if(retp > lastp) {
            log_debug("Access out of bounds");
            err = RESPONSE_ERR_PARAM_INVALID;
            break;
        }
        curparam = curparam->next;
        prevdecode = curdecode;
        curdecode = NULL;
    }
    if(err != RESPONSE_SUCCESS) {
        DecodeTFree(res->next);
        res->next = NULL;
        free(res->bytes);
        res->bytes = NULL;
        return err;
    }
    return err;
}


response_err_t DecodeRet(const abi_t* const abiroot, const ql_byte_t* const methodName, const ql_byte_t* const ret, decode_t* const res) {
    if(ret == NULL || strnlen(ret, 1) == 0){
        log_debug("no ret.\n");
        return RESPONSE_SUCCESS;
    }
    if(abiroot == NULL || methodName == NULL || res == NULL)return RESPONSE_ERR_PARAM_INVALID;
    param_t params;
    params.name = NULL;
    params.paramType = NULL;
    params.components = NULL;
    params.next = NULL;
    contract_err_t err = GetFuncOutput(abiroot, methodName, &params);
    if(err != CONTRACT_SUCCESS)return err;
    return decodeFromParam(&params, ret, res);
}

decode_t* CreateDecodeT() {
    decode_t* ret = (decode_t*)calloc(1, sizeof(decode_t));
    if(ret == NULL)return NULL;
    ret->bytes = NULL;
    ret->next = NULL;
    return ret;
}

void DecodeTFree(decode_t* in) {
    decode_t* now = in;
    while(in) {
        now = in;
        in = in->next;
        free(now->bytes);
        free(now);
    }
}
